package com.chatplus.application.common.util;

import com.chatplus.application.common.logging.SouthernQuietLogger;
import com.chatplus.application.common.logging.SouthernQuietLoggerFactory;

import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.util.stream.Stream;

/**
 * 用于测试单元,避免写多参数构造器
 *
 * @author
 */
public class UnitTestUtils {
    private static final SouthernQuietLogger LOGGER = SouthernQuietLoggerFactory.getLogger(UnitTestUtils.class);

    /**
     * @param targetClass   需要测试类, 需要有无参构造器
     * @param thisTestClass 当前单元测试类
     */
    public static <T> T buildBean(Class<T> targetClass, Object thisTestClass) {
        try {
            T instance = targetClass.getDeclaredConstructor().newInstance();
            Field[] declaredFields = targetClass.getDeclaredFields();
            Field[] superDeclaredFields = targetClass.getSuperclass().getDeclaredFields();
            Field[] fieldsValue = thisTestClass.getClass().getDeclaredFields();
            setFields(thisTestClass, instance, declaredFields, fieldsValue);
            setFields(thisTestClass, instance, superDeclaredFields, fieldsValue);
            return instance;
        } catch (InstantiationException | IllegalAccessException | InvocationTargetException | NoSuchMethodException e) {
            LOGGER.message("buildBean 异常").exception(e).error();
            throw new RuntimeException();
        }
    }


    private static <T> void setFields(Object test, T instance, Field[] superDeclaredFields, Field[] fieldsValue) {
        Stream.of(superDeclaredFields)
            .forEach(field -> {
                field.setAccessible(true);
                Stream.of(fieldsValue).filter(value -> field.getType().isAssignableFrom(value.getType()))
                    .findAny()
                    .ifPresent(value -> {
                        try {
                            Object o = field.get(instance);
                            if (o == null) {
                                value.setAccessible(true);
                                field.set(instance, value.get(test));
                            }
                        } catch (Exception e) {
                            LOGGER.message("setFields error").exception(e).error();
                        }
                    });
            });
    }
}
